/******************************************************************************
 * Copyright (C) 2015  671643387@qq.com
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License as published by the
 * Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
 * more details.
 *
 * You should have received a copy of the GNU General Public License along
 * with this program; if not, write to the Free Software Foundation, Inc.,
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
 *
 *****************************************************************************/

#include "Shared/DB/SQLStorage.h"
#include "Shared/DB/SQLStorageImpl.h"
using namespace Shared::DBC;


namespace Shared {
namespace DB {

    SQLStorageBase::SQLStorageBase() 
        : _tableName(NULL)
        , _entryField(NULL)
        , _srcFormat(NULL)
        , _dstFormat(NULL)

        , _dstFieldCount(0)
        , _srcFieldCount(0)
        , _recordCount(0)
        , _maxEntry(0)
        , _recordSize(0)

        , _data(NULL)
    {
    }

    void SQLStorageBase::initialize(const char* tableName, const char* entry_field, const char* src_format, const char* dst_format)
    {
        _tableName = tableName;
        _entryField = entry_field;
        _srcFormat = src_format;
        _dstFormat = dst_format;
    
        _srcFieldCount = strlen(_srcFormat);
        _dstFieldCount = strlen(_dstFormat);
    }
    
    char* SQLStorageBase::createRecord(std::uint32_t recordId)
    {
        char* newRecord = &_data[_recordCount * _recordSize];
        ++_recordCount;
    
        justCreatedRecord(recordId, newRecord);
        return newRecord;
    }
    
    void SQLStorageBase::prepareToLoad(std::uint32_t maxEntry, std::uint32_t recordCount, std::uint32_t recordSize)
    {
        _maxEntry = maxEntry;
        _recordSize = recordSize;
    
        delete[] _data;
        _data = new char[recordCount * _recordSize];
        memset(_data, 0, recordCount * _recordSize);
    
        _recordCount = 0;
    }
    
    void SQLStorageBase::free()
    {
        if (!_data)
        { return; }
    
        std::uint32_t offset = 0;
        for (std::uint32_t x = 0; x < _dstFieldCount; ++x)
        {
            switch (_dstFormat[x])
            {
            case DBC_FF_LOGIC:
                offset += sizeof(bool);
                break;
            case DBC_FF_STRING:
                {
                    for (std::uint32_t recordItr = 0; recordItr < _recordCount; ++recordItr)
                    { delete[] *(char**)((char*)(_data + (recordItr * _recordSize)) + offset); }
    
                    offset += sizeof(char*);
                    break;
                }
            case DBC_FF_NA:
            case DBC_FF_INT:
                offset += sizeof(std::uint32_t);
                break;
            case DBC_FF_BYTE:
            case DBC_FF_NA_BYTE:
                offset += sizeof(char);
                break;
            case DBC_FF_FLOAT:
            case DBC_FF_NA_FLOAT:
                offset += sizeof(float);
                break;
            case DBC_FF_NA_POINTER:
                // TODO- possible (and small) memleak here possible
                offset += sizeof(char*);
                break;
            case DBC_FF_IND:
            case DBC_FF_SORT:
                assert(false && "SQL storage not have sort field types");
                break;
            default:
                assert(false && "unknown format character");
                break;
            }
        }
        delete[] _data;
        _data = NULL;
        _recordCount = 0;
    }



    void SQLStorage::eraseEntry(std::uint32_t id)
    {
        _index[id] = NULL;
    }

    void SQLStorage::free()
    {
        SQLStorageBase::free();
        delete[] _index;
        _index = NULL;
    }

    void SQLStorage::load(Shared::Database &db, bool error_at_empty /*= true*/)
    {
        SQLStorageLoader loader;
        loader.load(db, *this, error_at_empty);
    }

    SQLStorage::SQLStorage(const char* fmt, const char* _entry_field, const char* sqlname)
    {
        initialize(sqlname, _entry_field, fmt, fmt);
        _index = NULL;
    }

    SQLStorage::SQLStorage(const char* src_fmt, const char* dst_fmt, const char* _entry_field, const char* sqlname)
    {
        initialize(sqlname, _entry_field, src_fmt, dst_fmt);
        _index = NULL;
    }

    void SQLStorage::prepareToLoad(std::uint32_t maxRecordId, std::uint32_t recordCount, std::uint32_t recordSize)
    {
        // Clear (possible) old data and old index array
        free();

        // Set index array
        _index = new char*[maxRecordId];
        memset(_index, 0, maxRecordId * sizeof(char*));

        SQLStorageBase::prepareToLoad(maxRecordId, recordCount, recordSize);
    }



    void SQLHashStorage::load(Shared::Database &db)
    {
        SQLHashStorageLoader loader;
        loader.load(db, *this);
    }

    void SQLHashStorage::free()
    {
        SQLStorageBase::free();
        _indexMap.clear();
    }

    void SQLHashStorage::prepareToLoad(std::uint32_t maxRecordId, std::uint32_t recordCount, std::uint32_t recordSize)
    {
        // Clear (possible) old data and old index array
        free();

        SQLStorageBase::prepareToLoad(maxRecordId, recordCount, recordSize);
    }

    void SQLHashStorage::eraseEntry(std::uint32_t id)
    {
        // do not erase from m_records
        RecordMap::iterator find = _indexMap.find(id);
        if (find != _indexMap.end())
        { find->second = NULL; }
    }

    SQLHashStorage::SQLHashStorage(const char* fmt, const char* _entry_field, const char* sqlname)
    {
        initialize(sqlname, _entry_field, fmt, fmt);
    }

    SQLHashStorage::SQLHashStorage(const char* src_fmt, const char* dst_fmt, const char* _entry_field, const char* sqlname)
    {
        initialize(sqlname, _entry_field, src_fmt, dst_fmt);
    }



    void SQLMultiStorage::load(Shared::Database &db)
    {
        SQLMultiStorageLoader loader;
        loader.load(db, *this);
    }

    void SQLMultiStorage::free()
    {
        SQLStorageBase::free();
        _indexMultiMap.clear();
    }

    void SQLMultiStorage::prepareToLoad(std::uint32_t maxRecordId, std::uint32_t recordCount, std::uint32_t recordSize)
    {
        // Clear (possible) old data and old index array
        free();

        SQLStorageBase::prepareToLoad(maxRecordId, recordCount, recordSize);
    }

    void SQLMultiStorage::eraseEntry(std::uint32_t id)
    {
        _indexMultiMap.erase(id);
    }

    SQLMultiStorage::SQLMultiStorage(const char* fmt, const char* _entry_field, const char* sqlname)
    {
        initialize(sqlname, _entry_field, fmt, fmt);
    }

    SQLMultiStorage::SQLMultiStorage(const char* src_fmt, const char* dst_fmt, const char* _entry_field, const char* sqlname)
    {
        initialize(sqlname, _entry_field, src_fmt, dst_fmt);
    }
}}